package com.shuyihui.rxhttp.utils

import android.content.Context
import android.net.ConnectivityManager
import android.os.Looper
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import java.io.Closeable
import java.io.File
import java.io.IOException
import java.lang.reflect.GenericArrayType
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.lang.reflect.TypeVariable
import java.util.*

/**
 *
 * 描述：工具类
 */
object Utils {
    @JvmStatic
    fun <T> checkNotNull(t: T?, message: String?): T {
        if (t == null) {
            throw NullPointerException(message)
        }
        return t
    }

    fun checkMain(): Boolean {
        return Thread.currentThread() === Looper.getMainLooper().thread
    }

    fun createJson(jsonString: String): RequestBody {
        checkNotNull(jsonString, "json not null!")
        return RequestBody.create("application/json; charset=utf-8".toMediaTypeOrNull(), jsonString)
    }

    /**
     * @param name
     * @return
     */
    fun createFile(name: String): RequestBody {
        checkNotNull(name, "name not null!")
        return RequestBody.create("multipart/form-data; charset=utf-8".toMediaTypeOrNull(), name)
    }

    /**
     * @param file
     * @return
     */
    fun createFile(file: File): RequestBody {
        checkNotNull(file, "file not null!")
        return RequestBody.create("multipart/form-data; charset=utf-8".toMediaTypeOrNull(), file)
    }

    /**
     * @param file
     * @return
     */
    fun createImage(file: File): RequestBody {
        checkNotNull(file, "file not null!")
        return RequestBody.create("image/jpg; charset=utf-8".toMediaTypeOrNull(), file)
    }

    @JvmStatic
    fun close(close: Closeable?) {
        if (close != null) {
            try {
                closeThrowException(close)
            } catch (ignored: IOException) {
            }
        }
    }

    @Throws(IOException::class)
    fun closeThrowException(close: Closeable?) {
        close?.close()
    }

    /**
     * find the type by interfaces
     *
     * @param cls
     * @param <R>
     * @return
    </R> */
    fun <R> findNeedType(cls: Class<R>): Type {
        val typeList = getMethodTypes(cls)
        return if (typeList == null || typeList.isEmpty()) {
            RequestBody::class.java
        } else typeList[0]
    }

    /**
     * MethodHandler
     */
    fun <T> getMethodTypes(cls: Class<T>): List<Type>? {
        val typeOri = cls.genericSuperclass
        var needtypes: MutableList<Type>? = null
        // if Type is T
        if (typeOri is ParameterizedType) {
            needtypes = ArrayList()
            val parentypes = typeOri.actualTypeArguments
            for (childtype in parentypes) {
                needtypes.add(childtype)
                if (childtype is ParameterizedType) {
                    val childtypes = childtype.actualTypeArguments
                    Collections.addAll(needtypes, *childtypes)
                }
            }
        }
        return needtypes
    }

    fun getClass(type: Type, i: Int): Class<*> {
        return if (type is ParameterizedType) { // 处理泛型类型
            getGenericClass(
                type,
                i
            )
        } else if (type is TypeVariable<*>) {
            getClass(
                type.bounds[0], 0
            ) // 处理泛型擦拭对象
        } else { // class本身也是type，强制转型
            type as Class<*>
        }
    }

    fun getType(type: Type, i: Int): Type {
        return if (type is ParameterizedType) { // 处理泛型类型
            getGenericType(
                type,
                i
            )
        } else if (type is TypeVariable<*>) {
            getType(
                type.bounds[0], 0
            ) // 处理泛型擦拭对象
        } else { // class本身也是type，强制转型
            type
        }
    }

    @JvmStatic
    fun getParameterizedType(type: Type, i: Int): Type {
        return if (type is ParameterizedType) { // 处理泛型类型
            type.actualTypeArguments[i]
        } else if (type is TypeVariable<*>) {
            getType(type.bounds[0], 0) // 处理泛型擦拭对象
        } else { // class本身也是type，强制转型
            type
        }
    }

    fun getGenericClass(parameterizedType: ParameterizedType, i: Int): Class<*> {
        val genericClass = parameterizedType.actualTypeArguments[i]
        return if (genericClass is ParameterizedType) { // 处理多级泛型
            genericClass.rawType as Class<*>
        } else if (genericClass is GenericArrayType) { // 处理数组泛型
            genericClass.genericComponentType as Class<*>
        } else if (genericClass is TypeVariable<*>) { // 处理泛型擦拭对象
            getClass(
                genericClass.bounds[0], 0
            )
        } else {
            genericClass as Class<*>
        }
    }

    fun getGenericType(parameterizedType: ParameterizedType, i: Int): Type {
        val genericType = parameterizedType.actualTypeArguments[i]
        return if (genericType is ParameterizedType) { // 处理多级泛型
            genericType.rawType
        } else if (genericType is GenericArrayType) { // 处理数组泛型
            genericType.genericComponentType
        } else if (genericType is TypeVariable<*>) { // 处理泛型擦拭对象
            getClass(
                genericType.bounds[0], 0
            )
        } else {
            genericType
        }
    }

    fun isNetworkAvailable(context: Context): Boolean {
        val manager = context.applicationContext.getSystemService(
            Context.CONNECTIVITY_SERVICE
        ) as ConnectivityManager ?: return false
        val info = manager.activeNetworkInfo
        return if (null == info || !info.isAvailable) false else true
    }

    /**
     * 普通类反射获取泛型方式，获取需要实际解析的类型
     *
     * @param <T>
     * @return
    </T> */
    fun <T> findNeedClass(cls: Class<T>): Type {
        //以下代码是通过泛型解析实际参数,泛型必须传
        val genType = cls.genericSuperclass
        val params = (genType as ParameterizedType).actualTypeArguments
        val type = params[0]
        val finalNeedType: Type
        finalNeedType = if (params.size > 1) { //这个类似是：CacheResult<SkinTestResult> 2层
            check(type is ParameterizedType) { "没有填写泛型参数" }
            type.actualTypeArguments[0]
            //Type rawType = ((ParameterizedType) type).getRawType();
        } else { //这个类似是:SkinTestResult  1层
            type
        }
        return finalNeedType
    }

    /**
     * 普通类反射获取泛型方式，获取最顶层的类型
     */
    fun <T> findRawType(cls: Class<T>): Type {
        val genType = cls.genericSuperclass
        return getGenericType(genType as ParameterizedType, 0)
    }
}